#include "sdcard.h"
#include "stm32f4xx.h"
#include "string.h"
#include <rtthread.h>
#include <dfs_fs.h>

#define SDIO_CMD_PIN_PORT       GPIOD
#define SDIO_CMD_PIN        GPIO_PIN_2

#define SDIO_DATA_CLK_PIN_PORT  GPIOC
#define SDIO_DATA0_PIN      GPIO_PIN_8
#define SDIO_DATA1_PIN      GPIO_PIN_9
#define SDIO_DATA2_PIN      GPIO_PIN_10
#define SDIO_DATA3_PIN      GPIO_PIN_11
#define SDIO_CLK_PIN        GPIO_PIN_12


SD_HandleTypeDef        SDCARD_Handler;
HAL_SD_CardInfoTypedef  SDCardInfo;         //SD卡信息结构体
DMA_HandleTypeDef SDTxDMAHandler, SDRxDMAHandler;   //SD卡DMA发送和接收句柄


/**
 * @desc  : 初始化WIFI模块reset引脚并禁用wifi功能 否则sdio会初始化失败
 * @param : none
 * @return: none
 */
static void WIFI_EMW1062_disable(void)
{
    GPIO_InitTypeDef GPIO_Initure;

    __HAL_RCC_GPIOG_CLK_ENABLE();   //使能GPIOG时钟

    GPIO_Initure.Pin = GPIO_PIN_9;
    GPIO_Initure.Mode = GPIO_MODE_AF_PP;    //推挽复用
    GPIO_Initure.Pull = GPIO_PULLUP;        //上拉
    GPIO_Initure.Speed = GPIO_SPEED_HIGH;   //高速
    HAL_GPIO_Init(GPIOG, &GPIO_Initure);    //初始化

    HAL_GPIO_WritePin(GPIOG, GPIO_PIN_9, GPIO_PIN_RESET);
}

/**
 * @desc  : SD卡初始化
 * @param : none
 * @return: 0 初始化正确；其他值，初始化错误
 */
rt_uint8_t SD_Init(void)
{
    rt_uint8_t SD_Error;

    //初始化时的时钟不能大于400KHZ
    SDCARD_Handler.Instance = SDIO;
    SDCARD_Handler.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;        //上升沿
    SDCARD_Handler.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;   //不使用bypass模式，直接用HCLK进行分频得到SDIO_CK
    SDCARD_Handler.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;  //空闲时不关闭时钟电源
    SDCARD_Handler.Init.BusWide = SDIO_BUS_WIDE_1B;                      //1位数据线
    SDCARD_Handler.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; //关闭硬件流控
    SDCARD_Handler.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;          //SD传输时钟频率最大25MHZ

    SD_Error = HAL_SD_Init(&SDCARD_Handler, &SDCardInfo);
    if (SD_Error != SD_OK) return 1;

    SD_Error = HAL_SD_WideBusOperation_Config(&SDCARD_Handler, SDIO_BUS_WIDE_4B); //使能宽总线模式
    if (SD_Error != SD_OK) return 2;
    return 0;
}


/**
 * @desc  : SDMMC底层驱动，时钟使能，引脚配置，DMA配置
            此函数会被HAL_SD_Init()调用
 * @param : hsd SD卡句柄
 * @return: none
 */
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
{
    DMA_HandleTypeDef TxDMAHandler, RxDMAHandler;
    GPIO_InitTypeDef GPIO_Initure;

    __HAL_RCC_SDIO_CLK_ENABLE();    //使能SDIO时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟
    __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟
#ifdef SD_USE_DMA
    __HAL_RCC_DMA2_CLK_ENABLE();    //使能DMA2时钟
#endif

    //PC8,9,10,11,12
    GPIO_Initure.Pin = SDIO_DATA0_PIN | SDIO_DATA1_PIN | SDIO_DATA2_PIN | SDIO_DATA3_PIN | SDIO_CLK_PIN;
    GPIO_Initure.Mode = GPIO_MODE_AF_PP;    //推挽复用
    GPIO_Initure.Pull = GPIO_PULLUP;        //上拉
    GPIO_Initure.Speed = GPIO_SPEED_HIGH;   //高速
    GPIO_Initure.Alternate = GPIO_AF12_SDIO; //复用为SDIO
    HAL_GPIO_Init(SDIO_DATA_CLK_PIN_PORT, &GPIO_Initure);    //初始化

    //PD2
    GPIO_Initure.Pin = SDIO_CMD_PIN;
    HAL_GPIO_Init(SDIO_CMD_PIN_PORT, &GPIO_Initure);    //初始化

#ifdef SD_USE_DMA
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 2, 0); //配置SDMMC1中断，抢占优先级2，子优先级0
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);        //使能SDMMC1中断

    //配置发送DMA
    SDRxDMAHandler.Instance = DMA2_Stream3;
    SDRxDMAHandler.Init.Channel = DMA_CHANNEL_4;
    SDRxDMAHandler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    SDRxDMAHandler.Init.PeriphInc = DMA_PINC_DISABLE;
    SDRxDMAHandler.Init.MemInc = DMA_MINC_ENABLE;
    SDRxDMAHandler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    SDRxDMAHandler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    SDRxDMAHandler.Init.Mode = DMA_PFCTRL;
    SDRxDMAHandler.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    SDRxDMAHandler.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    SDRxDMAHandler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    SDRxDMAHandler.Init.MemBurst = DMA_MBURST_INC4;
    SDRxDMAHandler.Init.PeriphBurst = DMA_PBURST_INC4;

    __HAL_LINKDMA(hsd, hdmarx, SDRxDMAHandler); //将接收DMA和SD卡的发送DMA连接起来
    HAL_DMA_DeInit(&SDRxDMAHandler);
    HAL_DMA_Init(&SDRxDMAHandler);              //初始化接收DMA

    //配置接收DMA
    SDTxDMAHandler.Instance = DMA2_Stream6;
    SDTxDMAHandler.Init.Channel = DMA_CHANNEL_4;
    SDTxDMAHandler.Init.Direction = DMA_MEMORY_TO_PERIPH;
    SDTxDMAHandler.Init.PeriphInc = DMA_PINC_DISABLE;
    SDTxDMAHandler.Init.MemInc = DMA_MINC_ENABLE;
    SDTxDMAHandler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    SDTxDMAHandler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    SDTxDMAHandler.Init.Mode = DMA_PFCTRL;
    SDTxDMAHandler.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    SDTxDMAHandler.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    SDTxDMAHandler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    SDTxDMAHandler.Init.MemBurst = DMA_MBURST_INC4;
    SDTxDMAHandler.Init.PeriphBurst = DMA_PBURST_INC4;

    __HAL_LINKDMA(hsd, hdmatx, SDTxDMAHandler);//将发送DMA和SD卡的发送DMA连接起来
    HAL_DMA_DeInit(&SDTxDMAHandler);
    HAL_DMA_Init(&SDTxDMAHandler);              //初始化发送DMA

    HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 3, 0);  //接收DMA中断优先级
    HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
    HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 3, 0);  //发送DMA中断优先级
    HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
#endif
}

/**
 * @desc  : 获取卡信息
 * @param : cardinfo:卡信息存储区
 * @return: 错误状态
 */
rt_uint8_t SD_GetCardInfo(HAL_SD_CardInfoTypedef *cardinfo)
{
    rt_uint8_t sta;
    sta = HAL_SD_Get_CardInfo(&SDCARD_Handler, cardinfo);
    return sta;
}

/*********************************************
*                硬件读写驱动程序
*********************************************/
#ifdef SD_USE_DMA
/**
 * @desc  : 通过DMA读取SD卡一个扇区
 * @param : buf:读数据缓存区
 *          sector:扇区地址
 *          cnt:扇区个数
 * @return: 错误状态;0,正常;其他,错误代码
 */
rt_uint8_t SD_ReadBlocks_DMA(uint32_t *buf, uint64_t sector, uint32_t cnt)
{
    rt_uint8_t err = SD_OK;
    err = HAL_SD_ReadBlocks_DMA(&SDCARD_Handler, buf, sector, SECTOR_SIZE, cnt); //通过DMA读取SD卡一个扇区
    if (err == SD_OK) //读取成功
    {
        //等待读取完成
        err = HAL_SD_CheckReadOperation(&SDCARD_Handler, (uint32_t)SD_TIMEOUT);
    }

    return err;
}

/**
 * @desc  : 写SD卡扇区
 * @param : buf:写数据缓存区
 *          sector:扇区地址
 *          cnt:扇区个数
 * @return: 错误状态;0,正常;其他,错误代码
 */
rt_uint8_t SD_WriteBlocks_DMA(uint32_t *buf, uint64_t sector, uint32_t cnt)
{
    rt_uint8_t err = SD_OK;
    err = HAL_SD_WriteBlocks_DMA(&SDCARD_Handler, buf, sector, SECTOR_SIZE, cnt); //通过DMA写SD卡一个扇区
    if (err == SD_OK) //写成功
    {
        err = HAL_SD_CheckWriteOperation(&SDCARD_Handler, (uint32_t)SD_TIMEOUT); //等待读取完成/
    }
    return err;
}

//SDMMC1中断服务函数
void SDMMC1_IRQHandler(void)
{
    HAL_SD_IRQHandler(&SDCARD_Handler);
}

//DMA2数据流6中断服务函数
void DMA2_Stream6_IRQHandler(void)
{
    HAL_DMA_IRQHandler(SDCARD_Handler.hdmatx);
}

//DMA2数据流3中断服务函数
void DMA2_Stream3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(SDCARD_Handler.hdmarx);
}
#else
/**
 * @desc  : 读取SD卡一个扇区
 * @param : buf:读数据缓存区
 *          sector:扇区地址
 *          cnt:扇区个数
 * @return: 错误状态;0,正常;其他,错误代码
 */
rt_uint8_t SD_ReadBlocks(uint32_t *buf, uint64_t sector, uint32_t cnt)
{
    rt_uint8_t err = SD_OK;
    err = HAL_SD_ReadBlocks(&SDCARD_Handler, buf, sector, SECTOR_SIZE, cnt); //通过DMA读取SD卡一个扇区
    return err;
}

/**
 * @desc  : 写SD卡扇区
 * @param : buf:写数据缓存区
 *          sector:扇区地址
 *          cnt:扇区个数
 * @return: 错误状态;0,正常;其他,错误代码
 */
rt_uint8_t SD_WriteBlocks(uint32_t *buf, uint64_t sector, uint32_t cnt)
{
    return HAL_SD_WriteBlocks(&SDCARD_Handler, buf, sector, SECTOR_SIZE, cnt);
}
#endif  //SD_USE_DMA

/*********************************************
*                框架接口驱动程序
*********************************************/
static struct rt_device sdcard_device;
static struct rt_semaphore sd_lock;

/* RT-Thread Device Driver Interface */
static rt_err_t rt_sdcard_init(rt_device_t dev)
{
    if (rt_sem_init(&sd_lock, "sdlock", 1, RT_IPC_FLAG_FIFO) != RT_EOK)
    {
        rt_kprintf("init sd lock semaphore failed\n");
    }
    else
        rt_kprintf("SD Card init OK\n");

    return RT_EOK;
}

static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

static rt_err_t rt_sdcard_close(rt_device_t dev)
{
    return RT_EOK;
}

static uint32_t sdio_buffer[512 / sizeof(uint32_t)];
static rt_size_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    rt_uint8_t status = SD_OK;

    rt_sem_take(&sd_lock, RT_WAITING_FOREVER);

    if (((uint32_t)buffer & 0x03) != 0)
    {
        /* non-aligned. */
        uint32_t i;
        rt_size_t sector_adr;
        uint8_t *copy_buffer;

        sector_adr = pos * SECTOR_SIZE;
        copy_buffer = (uint8_t *)buffer;

        for (i = 0; i < size; i++)
        {
#ifdef SD_USE_DMA
            status = SD_ReadBlocks_DMA(sdio_buffer, sector_adr, 1); //通过DMA写SD卡一个扇区
#else
            status = SD_ReadBlocks(sdio_buffer, sector_adr, 1);
#endif
            memcpy(copy_buffer, sdio_buffer, SECTOR_SIZE);
            sector_adr += SECTOR_SIZE;
            copy_buffer += SECTOR_SIZE;
        }
    }
    else
    {
#ifdef SD_USE_DMA
        status = SD_ReadBlocks_DMA(buffer, pos * SECTOR_SIZE, size); //通过DMA写SD卡一个扇区
#else
        SD_ReadBlocks(buffer, pos * SECTOR_SIZE, size);
#endif
    }

    rt_sem_release(&sd_lock);
    if (status == SD_OK) return size;

    rt_kprintf("read failed: %d, buffer 0x%08x\n", status, buffer);
    return 0;
}

static rt_size_t rt_sdcard_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    rt_uint8_t status = SD_OK;
    rt_sem_take(&sd_lock, RT_WAITING_FOREVER);

    if (((uint32_t)buffer & 0x03) != 0)
    {
        /* non-aligned. */
        uint32_t i;
        rt_size_t sector_adr;
        uint8_t *copy_buffer;

        sector_adr = pos * SECTOR_SIZE;
        copy_buffer = (uint8_t *)buffer;

        for (i = 0; i < size; i++)
        {
            memcpy(sdio_buffer, copy_buffer, SECTOR_SIZE);
#ifdef SD_USE_DMA
            status = SD_WriteBlocks_DMA((uint32_t *)sdio_buffer, sector_adr, 1);
#else
            status = SD_WriteBlocks((uint32_t *)sdio_buffer, sector_adr, 1);
#endif
            sector_adr += SECTOR_SIZE;
            copy_buffer += SECTOR_SIZE;

        }
    }
    else
    {
#ifdef SD_USE_DMA
        status = SD_WriteBlocks_DMA((uint32_t *)buffer, pos * SECTOR_SIZE, size);
#else
        status = SD_WriteBlocks((uint32_t *)buffer, pos * SECTOR_SIZE, size);
#endif
    }

    rt_sem_release(&sd_lock);
    if (status == SD_OK) return size;

    rt_kprintf("write failed: %d, buffer 0x%08x\n", status, buffer);
    return 0;
}

static rt_err_t rt_sdcard_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
    RT_ASSERT(dev != RT_NULL);

    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
    {
        struct rt_device_blk_geometry *geometry;

        geometry = (struct rt_device_blk_geometry *)args;
        if (geometry == RT_NULL) return -RT_ERROR;

        geometry->bytes_per_sector = 512;
        geometry->block_size = SDCardInfo.CardBlockSize;
        geometry->sector_count = SDCardInfo.CardCapacity / SDCardInfo.CardBlockSize;
    }

    return RT_EOK;
}


int rt_hw_sdcard_init(void)
{
    WIFI_EMW1062_disable();

    if (SD_Init() == SD_OK)
    {
        /* register sdcard device */
        sdcard_device.type  = RT_Device_Class_Block;
        sdcard_device.init  = rt_sdcard_init;
        sdcard_device.open  = rt_sdcard_open;
        sdcard_device.close = rt_sdcard_close;
        sdcard_device.read  = rt_sdcard_read;
        sdcard_device.write = rt_sdcard_write;
        sdcard_device.control = rt_sdcard_control;

        /* no private */
        sdcard_device.user_data = &SDCardInfo;

        rt_device_register(&sdcard_device, "sd0",
                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);

        return RT_EOK;
    }
    rt_kprintf("sdcard init failed\n");
    return RT_ERROR;
}
// INIT_BOARD_EXPORT(rt_hw_sdcard_init);
